/*
 Copyright (c) 2013 MeherTJ G. All rights reserved.
 License: LGPL for personnal study or free software.
 */

#include "zen_file.h"
#include "zen_exception.h"
#include "zen_endian.h"
#include "zen_audio.h"

namespace Zen {
	class AudioRaw : public AudioDecoder, public AudioEncoder
	{
	public:
		// throw (Zen::Exception)
		std::shared_ptr<Audio> decode(const std::vector<uint8_t>& value) override;

		// throw (Zen::Exception)
		std::vector<uint8_t> encode(const Zen::Audio&) override;
	};
}

////////////////////////
////////////////////////
namespace Zen {
	struct AudioRawHead
	{
		// dont change the order of these members.
		uint32_t sign{};
		uint16_t channel{};
		uint16_t sample_size{};
		uint32_t frequency{};
		uint32_t sample_count{};

		void Set(size_t channel, size_t sample_size, size_t frequency, size_t sample_count)
		{
			this->sign = Byte4('j', 'a', 'i', 'w').value;
			this->channel = HostNet16((uint16_t)channel);
			this->sample_size = HostNet16((uint16_t)sample_size);
			this->frequency = HostNet32((uint32_t)frequency);
			this->sample_count = HostNet32((uint32_t)sample_count);
		}
	};

	inline std::shared_ptr<Audio> AudioRaw::decode(const std::vector<uint8_t>& value)
	{
		AudioRawHead head;

		__zen_must_else(value.size() >= sizeof(head), "failed to read header");
		::memcpy(&head, value.data(), sizeof(head));

		auto channel = HostNet16(head.channel);
		auto sample_size = HostNet16(head.sample_size);
		auto frequency = HostNet32(head.frequency);
		auto sample_count = HostNet32(head.sample_count);

		uint32_t size = sample_size * sample_count;

		__zen_must_else(size > 0, "invalid file format");

		__zen_must_else(value.size() >= sizeof(head) + size, "invalid file content");

		auto audio = Audio::Generate(channel, sample_size, frequency, sample_count);
		__zen_must(size == audio->size());
		::memcpy(audio->data(), value.data() + sizeof(head), size);
		return audio;
	}
	inline std::vector<uint8_t> AudioRaw::encode(const Zen::Audio& audio)
	{
		AudioRawHead head;
		head.Set(audio.channel(), audio.sampleSize(), audio.frequency(), audio.sampleCount());
		std::vector<uint8_t> value;
		value.reserve(sizeof(head) + audio.size());

		auto head_buf = reinterpret_cast<char const*>(&head);
		value.assign(head_buf, head_buf + sizeof(head));
		value.insert(value.end(), audio.data(), audio.data() + audio.size());
		return value;
	}
}


